home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / program / oxcc1434.zip / SRC / PARSER.C < prev    next >
C/C++ Source or Header  |  1995-10-18  |  43KB  |  1,824 lines

  1. /* parser.c -- derived from the `LALR' parser written by Paul Mann */
  2.  
  3. #define CLASS Parser
  4.  
  5. #include <oxbow.h>
  6.  
  7. object CLASS;
  8.  
  9. instanceVars {
  10.     PG pg;
  11. };
  12. #define HOWBIG 1
  13. #define DEBUG 1
  14.  
  15. #if HOWBIG
  16. static int maxXX_parse;
  17. static int maxSS_parse;
  18. static int maxSS_lex;
  19. static int maxNS_parse;
  20. static int maxLS_parse;
  21. static int maxRS_parse;
  22. #endif
  23.  
  24.  
  25. /* Built in standard actions */
  26. static void nullaction();
  27. static void classify();
  28. static void require();
  29. static void doline();
  30. static void dyntoken();
  31.  
  32. static void LoadParserPointers();
  33.  
  34. /* some imported functions */
  35. char *strchr();
  36. char *strrchr();
  37. int atol();
  38. int _strcpy(void *dst, const void *src);
  39. void *strcpy(void *dst, const void *src);
  40. void *strcat(void *dst, const void *src);
  41. void *memcpy(void *dst, const void *src, int len);
  42.  
  43.  
  44. /* All chunk types have the same number of bytes */
  45.  
  46. #define ASTCHUNK (pg->astchunk)
  47. #define SYMBOLCHUNK (pg->symbolchunk)
  48. #define TEXTCHUNK (pg->textchunk)
  49. #define ASTSIZE (pg->astsize)
  50.  
  51.  
  52. typedef struct _key
  53. {
  54.     unsigned long key;
  55.     unsigned long hv;
  56. } KEY, *KEYP;
  57.  
  58. typedef struct _psym
  59. {/* Fits in a minimal sized AST node */
  60.     unsigned short dat[4];        /* 8 bytes */
  61.     KEY cat;                    /* 8 bytes */
  62.     struct _psym *next;            /* 4 bytes */
  63. } Psym, *PsymP;
  64.  
  65. typedef struct _pbuf
  66. {/* parser symbol table struct */
  67.     int    size;
  68.     void *lastbin;    /* for DelLast */
  69.     int headbin;    /* for seq access */
  70.     PsymP headptr;    /* ditto */
  71.     PG *wpg;
  72.     PsymP bins[0];
  73. } *PbufP;
  74.  
  75. void *
  76. NewParserSymTable(PG *pg, int size)
  77. {
  78. PbufP buf = callocC(pg->category, 1, size*sizeof(PsymP) + sizeof(struct _pbuf));
  79.     buf->size = size;
  80.     buf->wpg = pg;
  81.     return buf;
  82. }
  83.  
  84. cmethod vobject
  85. New(object self, char *language, int astsize)
  86. {
  87. void *lfile;
  88. char lodname[200];
  89. char filename[40];
  90. char *cp;
  91. PTABLE *pp;
  92. LTABLE *lp;
  93. long *symbase;
  94. char *symptr;
  95. char buf[100];
  96. Item item;
  97. int i;
  98. object instance;
  99. PG *pg;
  100. int oldload = 0;
  101. AstP fnode;
  102.  
  103.     if(IsaClass(self))
  104.         instance  = cSuper(gNew)(self);
  105.     else {
  106.         instance = self;
  107.     }
  108.     pg = (PG *)ivPtr(instance);
  109.     pg->category = NewMallocCategory();
  110.  
  111.     strcpy(pg->language, language);
  112.     strcpy(filename, language);
  113.     strcat(filename, ".lod");
  114.  
  115.     if((cf_find_file("oxlib.cff", lodname)))
  116.     {/* The archive file */
  117.         strcat(lodname, "/language/");
  118.         strcat(lodname, filename);
  119.     } else {
  120.         pg->errors = 1;
  121.         return instance;
  122.     }
  123.     if(cfqget(MEMTEMP, filename, strlen(filename), &item, 8) == FOUND)
  124.     {/* Parser tables for this language have been loaded earlier */
  125.         pg->lod_table = item.a1;
  126.         oldload = 1;
  127.     }
  128.     else
  129.     {/* Load the parser tables for this language */
  130.         if((lfile = cfopen(lodname, F_STAT, NULL)))
  131.         {
  132.         int size;
  133.             size = cfseek(lfile, 0, S_END);
  134.             pg->lod_table = malloc(size);
  135.             cfseek(lfile, 0, S_SET);
  136.             cfread(lfile, pg->lod_table, size);
  137.             cfclose(lfile);
  138.             item.item = 0;
  139.             item.a1 = pg->lod_table;
  140.             cfinsert(MEMTEMP, filename, strlen(filename), &item);
  141.         }
  142.         else {
  143.             pg->errors = 2;
  144.             return instance;
  145.         }
  146.     }
  147.  
  148.     /* using the size of the caller's AST node, compute suitable chunks */
  149.  
  150.     if(astsize < sizeof(AST_NODE))
  151.         astsize = sizeof(AST_NODE);
  152.  
  153.     if(astsize & 3)
  154.         astsize += 4-(astsize&3);
  155.  
  156.     ASTCHUNK = 8184/astsize;
  157.     TEXTCHUNK = ASTCHUNK * astsize;
  158.     SYMBOLCHUNK = TEXTCHUNK / 4;
  159.     ASTSIZE = astsize;
  160.     
  161.     /* Parser table init */
  162.     pg->ptab = callocC(pg->category, 1, sizeof(PTABLE));    
  163.     pp = pg->ptab;
  164.     pp->pg = pg;
  165.     LoadParserPointers(pp, pg->lod_table, 1);
  166.     pp->linksize = SYMBOLCHUNK;
  167.     pp->link = callocC(pg->category, 1, SYMBOLCHUNK*sizeof(void*));
  168.  
  169.  
  170.     /* Lexer table init */
  171.     pg->ltab = callocC(pg->category, 1, sizeof(LTABLE));
  172.     lp = pg->ltab;
  173.     lp->pg = pg;
  174.     LoadParserPointers(lp, (LODTABLE *)(((char *)pg->lod_table) + pg->lod_table->next), 0);
  175.  
  176.     /* Action pointers, applies to both parser and lexer */
  177.     pg->n_actions = lp->n_actions;    /* lexer has the best action count */
  178.     pg->ACTIONS = (PACTIONS)lp->ACTIONS;
  179.     pg->ACTIONSTRINGS = lp->ACTIONSTRINGS;
  180.  
  181.     /* Allocate the initial ast space */
  182.     pg->pat.free = callocC(pg->category, 1, ASTCHUNK*astsize);    
  183.     pg->pat.freecnt = pg->pat.cnt = ASTCHUNK;
  184.     fnode = pg->pat.free;
  185.     for(i = 0; i < ASTCHUNK-1; ++i)
  186.     {
  187.         fnode->down = (AstP)(((char*)fnode)+ASTSIZE);
  188.         fnode = fnode->down;
  189.     }
  190.  
  191.     /* Allocate and initialize the parser symbol table */
  192.     PARSERSYMBOLS = callocC(pg->category, 1, SYMBOLCHUNK*sizeof(PARSER_SYMBOL));
  193.     pg->symhandle = NewParserSymTable(pg, 2003);
  194.  
  195.     /* Allocate and initialize the first text accumulation chunk */
  196.     pg->chunkbase = callocC(pg->category, 1, TEXTCHUNK);
  197.     pg->chunkend = pg->chunkbase+TEXTCHUNK-1;
  198.     pg->symbase = pg->chunkbase+4;
  199.     pg->symend = pg->symbase;
  200.  
  201.     /* Enter all the terminal symbols of the grammar */
  202.     symbase = pp->G_symbol;
  203.     symptr = (char *)symbase;
  204.  
  205.     for(i = 0; i < pp->n_terms; ++i)
  206.     {
  207.         NewParserSymbol(pg, symptr+symbase[i]);
  208.     }
  209.  
  210.     /* Set the values for the automatic node ids */
  211.     {
  212.     int    symnum = -1;
  213.     int symval;
  214.     int subsym = 0;
  215.     char *cp = NULL;
  216.         for(i = 0; i < pp->n_rules; ++i)
  217.         {
  218.         long *vp;    /* assume callers node ids are sizeof(long) */
  219.             if(pp->PL[i] & PL_MAKENODE)
  220.             {
  221.                 if(pp->Head[i] != symnum)
  222.                 {
  223.                     subsym = 0;
  224.                     symnum = pp->Head[i];
  225.                     cp = symptr + symbase[symnum];
  226.                 }
  227.                 /* e.g. _cInitDeclarator_0 */
  228.                 cfsprintf(buf, "_%s%s_%d", pg->language, cp, subsym);
  229.  
  230.                 /* use dynamic linker here */
  231.                 symval = (symnum<<6) | subsym;
  232.                 if((vp = oxlink_find_bare_symb(buf)) != NULL)
  233.                 {/* vp is now the address of the symbol in caller memory */
  234.                     *vp = symval;  /* caller defined a global symbol he wants */
  235.                 }
  236.                 ++subsym;
  237.             }
  238.         }
  239.     }
  240.     /* Set up the function pointers for actions */
  241.     if(!oldload)
  242.     {/* THIS WOULD WORK WITHOUT TESTING FOR 'oldload', just saving time */
  243.     PACTIONS pa = pg->ACTIONS;
  244.     char *cp;
  245.     int mask;
  246.     int j;
  247.  
  248.         for(i = 0; i < pg->n_actions; ++i, ++pa)
  249.         {
  250.         /* 
  251.             pa->func is initially set to an offset into ACTIONSTRINGS 
  252.                     convert it into a function pointer
  253.         */
  254.             cp = pg->ACTIONSTRINGS + (int)pa->func; /* funcname is first entry */
  255.             if(!strcmp(cp, "classify"))
  256.                 pa->func = classify;
  257.             else if(!strcmp(cp, "require"))
  258.                 pa->func = require;
  259.             else if(!strcmp(cp, "doline"))
  260.                 pa->func = doline;
  261.             else if(!strcmp(cp, "dyntoken"))
  262.                 pa->func = dyntoken;
  263.             else
  264.             {/* Concoct the real user action name and find the function */
  265.                 /* e.g. _dosomething_ada_ */
  266.                 cfsprintf(buf, "_%s_%s_", cp, pg->language);
  267.                 if((pa->func = oxlink_find_bare_func(buf)) == NULL)
  268.                 {/* Not already in core */
  269.                     if((pa->func = oxlink_load_bare_symb(buf, 1)) == NULL)
  270.                     {/* And can't load it from the archive, punt to nothing */
  271.                         pa->func = nullaction;
  272.                     }
  273.                 }
  274.             }
  275.             /* 
  276.                 Set up the args:
  277.                 arg[0] contains a bitmask in the high order 16 bits
  278.                     and argcnt in the low 16 bits 
  279.             */
  280.             mask = (pa->args[0] & 0xffff0000) >> 16;
  281.             pa->args[0] &= 0x0000ffff;
  282.             for(j = 1; j <= pa->args[0]; ++j)
  283.             {
  284.                 if(mask & 1)
  285.                 {/* This arg is really a pointer to a string */
  286.                     pa->args[j] += (int)pg->ACTIONSTRINGS;
  287.                 }
  288.                 mask >>= 1;
  289.             }
  290.         }
  291.     }
  292.     /* Set a few constants */
  293.     pg->parsecnt = 2;
  294.     pg->ROOT = 0;
  295.     pg->root = 0;
  296.     pg->line_numb = 1;
  297.     pg->line_char = 0;
  298. #if HOWBIG
  299.     maxXX_parse = 
  300.         maxSS_parse =
  301.             maxSS_lex =
  302.                 maxNS_parse =
  303.                     maxLS_parse = 
  304.                         maxRS_parse = 0;
  305. #endif
  306.     return instance;
  307. }
  308. imethod void
  309. Dispose(object self)
  310. {
  311. PG *pg = (PG *)ivPtr(self);
  312.  
  313.     freecat(pg->category);
  314.     super(gDispose)(self);
  315. }
  316.  
  317.  
  318. static unsigned short bitlist[16] = {
  319.             0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
  320.             0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
  321.     };
  322. #define BITSET(a,b,c) ( a[b+(c>>4)] & bitlist[c&0xf] )
  323.  
  324. static int
  325. do_parse (PTABLE *ptab)
  326. {
  327. short i, x;
  328. short *r;
  329. short rule;
  330. unsigned base;
  331. short state;
  332. int token;
  333. short stacktop, *SS;
  334. PG *pg;
  335. int rulesize;
  336. int debug;
  337. int xx;
  338. AstP *link;
  339. int lexindx;
  340.  
  341. /* NESTED SUBROUTINE Make AST node and/or call semantic action. */
  342.  
  343. static void attach ()
  344. {
  345. int k, i, j;